//************************************************************************
// author	:	vera												
// date		:	2011/4/3 1:28 					                 
//************************************************************************
#ifndef SL_REF_PTR_H_
#define SL_REF_PTR_H_

namespace sl
{

	template < class T >
	class ref_ptr
	{
		public:
			ref_ptr(): m_pPtr(0){};
			ref_ptr( T * ptr ):m_pPtr(ptr){ if( m_pPtr ) m_pPtr->ref(); };
			ref_ptr( const ref_ptr<T> & rp ):m_pPtr(rp.m_pPtr) { if( m_pPtr ) m_pPtr->ref(); }
			template <class Other > ref_ptr( const ref_ptr< Other > & rp ):m_pPtr( rp.m_pPtr ) { if( m_pPtr ) m_pPtr->ref(); }
			~ref_ptr() { if ( m_pPtr ) m_pPtr->unref(); }
			
			ref_ptr & operator = ( T * ptr )
			{
				if ( m_pPtr == ptr )  return *this;

				T * tmp_ptr = m_pPtr;
				m_pPtr = ptr;

				if ( m_pPtr ) m_pPtr->ref();

				if ( tmp_ptr ) tmp_ptr->unref();

				return *this;
			}

			ref_ptr & operator = ( const ref_ptr & rhs )
			{
				assign( rhs );
				return *this;
			}

			template < class Other > ref_ptr & operator = ( const ref_ptr< Other > & rhs )
			{
				assign( rhs );
				return *this;
			}

			T * get() const { return m_pPtr; };
			T * operator-> () const { return m_pPtr;};
			T & operator* () { return *m_pPtr; };

			bool operator == ( const  ref_ptr * rp ) { return ( m_pPtr == rp.m_pPtr ); }
			bool operator == ( const T * ptr ) { return (m_pPtr == ptr );}
			friend bool operator == ( const T * ptr, const ref_ptr & rp ){ return (ptr == rp.m_pPtr); } 
			
			bool operator != ( const  ref_ptr * rp ) { return ( m_pPtr != rp.m_pPtr ); }
			bool operator != ( const T * ptr ) { return (m_pPtr != ptr );}
			friend bool operator != ( const T * ptr, const ref_ptr & rp ){ return (ptr != rp.m_pPtr); } 

			bool operator !() { return (m_pPtr == 0);}

			bool valid() const { return (m_pPtr != 0);}
		private:
			template < class Other > void assign( const ref_ptr< Other > & rp )
			{
				if ( m_pPtr == rp.m_pPtr )
					return;

				T * tmp_ptr = m_pPtr;
				m_pPtr = rp.m_pPtr;

				if ( m_pPtr ) m_pPtr->ref();
				tmp_ptr->unref();

			}

			T *		m_pPtr;
	};
}


#endif
